package com.frank.loadinglibrary.common;

import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.utils.geo.Point;

import java.util.*;

/**
 * @author : frank
 * @date : 2021/4/29 16:19
 */

public class BallFadingComponent extends BallLoadingComponent {

    private boolean enableScaleAnimator = true;

    private boolean colorPaletteOn = false;

    private int ballCount = 10;

    private int radiusPercent = 12;

    private Paint mPaint = new Paint();

    private boolean mHasAnimators;

    private HashMap<AnimatorValue, AnimatorValue.ValueUpdateListener> mUpdateListeners = new HashMap<>();

    private ArrayList<AnimatorValue> mAnimators;

    private int ballColor = Color.getIntColor("#efefef");

    //梵高星空色板
    private String[] skyColorArray = new String[]{"#263c8b", "#4e74a6", "#BDBF78", "#BFA524", "#2E231F"};
    //彩虹色板
    private String[] rainbowColorArray = new String[]{"#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#00FFFF", "#0000FF", "#8B00FF"};
    //紫罗兰色板
    private String[] violetColorArray = new String[]{"#B9BBCA", "#6B565F", "#6C4691", "#CCA8EE", "#C1CDC9"};
    //草莓色板
    private String[] strawberryColorArray = new String[]{"#F07484", "#B2DAC7", "#F5C194", "#F39894", "#FDF0EF"};
    //绿叶色板
    private String[] leafColorArray = new String[]{"#4B944B", "#2CBA30", "#46C78E", "#C0EADE", "#42CEB3"};


    //设置小球的色板，默认为梵高星空配色


    @Override
    public BallFadingComponent setColorPalette(String[] colorPalette) {
        super.setColorPalette(colorPalette);
        return this;
    }

    public BallFadingComponent setColorPaletteOn(boolean colorPaletteOn) {
        this.colorPaletteOn = colorPaletteOn;
        return this;
    }

    public BallFadingComponent setColorPaletteOn(boolean colorPaletteOn, String[] colorPalette) {
        this.colorPaletteOn = colorPaletteOn;
        this.colorPalette = colorPalette;
        return this;
    }

    /**
     * @param enableAlphaAnimator 是否包含启动透明度动画，默认是
     */
    public BallFadingComponent setEnableAlphaAnimator(boolean enableAlphaAnimator) {
        this.enableAlphaAnimator = enableAlphaAnimator;
        return this;
    }

    /**
     * @param enableScaleAnimator 是否包含启动缩放动画，默认是
     */
    public BallFadingComponent setEnableScaleAnimator(boolean enableScaleAnimator) {
        this.enableScaleAnimator = enableScaleAnimator;
        return this;
    }

    /**
     * @param enableRotationAnimator 是否包含整体旋转动画，默认否
     */
    public BallFadingComponent setEnableRotationAnimator(boolean enableRotationAnimator) {
        this.enableRotationAnimator = enableRotationAnimator;
        return this;
    }

    /**
     * 设置有多少个小球，默认是10个
     *
     * @param ballCount 小球数量
     */
    public BallFadingComponent setBallCount(int ballCount) {
        this.ballCount = ballCount;
        if (ballCount > scaleFloats.size()) {
            scaleFloats.clear();
        }
        for (int i = 0; i < ballCount; i++) {
            scaleFloats.add(SCALE);
            alphas.add(ALPHA);
        }
        return this;
    }

    /**
     * 设置小球半径占整个圆半径的比例，默认是十二分之一
     *
     * @param radiusPercent
     */
    public BallFadingComponent setRadiusPercent(int radiusPercent) {
        this.radiusPercent = radiusPercent;
        return this;
    }

    /**
     * 设置小球颜色，默认白色
     *
     * @param ballColor
     */
    public BallFadingComponent setBallColor(int ballColor) {
        this.ballColor = ballColor;
        return this;
    }

    public BallFadingComponent(Context context) {
        super(context);
        initUI();
    }

    public BallFadingComponent(Context context, AttrSet attrSet) {
        super(context, attrSet);
        initUI();
    }

    public static final float SCALE = 1.0f;

    public static final float ALPHA = 1.0f;

    ArrayList<Float> scaleFloats = new ArrayList<>();

    ArrayList<Float> alphas = new ArrayList<>();

    private void initUI() {
        for (int i = 0; i < ballCount; i++) {
            scaleFloats.add(SCALE);
            alphas.add(ALPHA);
        }
        DrawTask task = (component, canvas) -> {
            setPaint();
            draw(canvas, mPaint);
        };
        addDrawTask(task);

        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                if (autoStart) {
                    start();
                }
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {
            }
        });
        this.colorPalette = skyColorArray;
    }

    public void setPaint() {
        mPaint.setColor(new Color(ballColor));
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);
    }

    @Override
    public void addDrawTask(Component.DrawTask drawTask) {
        super.addDrawTask(drawTask);
        drawTask.onDraw(this, mCanvasForTaskOverContent);
    }


    public void draw(Canvas canvas, Paint paint) {
        float radius = getWidth() / radiusPercent;
        for (int i = 0; i < ballCount; i++) {
            canvas.save();
            Point point = circleAt(getWidth(), getHeight(), getWidth() / 2 - radius, i * (Math.PI * 2 / ballCount));
            canvas.translate(point.getPointX(), point.getPointY());
            canvas.scale(scaleFloats.get(i), scaleFloats.get(i));
            paint.setAlpha(alphas.get(i));
            if (colorPaletteOn) {
                Color currentColor = new Color(Color.getIntColor(colorPalette[i % colorPalette.length]));
                paint.setColor(currentColor);
            }
            canvas.drawCircle(0, 0, radius, paint);
            canvas.restore();
        }
    }

    public ArrayList<AnimatorValue> createAnimators() {
        ArrayList<AnimatorValue> animators = new ArrayList<>();
        for (int i = 0; i < ballCount; i++) {
            final int index = i;
            AnimatorValue scaleAnim = new AnimatorValue();
            scaleAnim.setDuration(1000);
            scaleAnim.setLoopedCount(-1);
            scaleAnim.setDelay(i * 120);
            addUpdateListener(scaleAnim, (animatorValue, v) -> {
                if (v < 0.5f) {
                    scaleFloats.set(index, (float) (-1.2 * v + 1));
                } else {
                    scaleFloats.set(index, (float) (1.2 * v - 0.2));
                }

                invalidate();
            });

            AnimatorValue alphaAnim = new AnimatorValue();
            alphaAnim.setDuration(1000);
            alphaAnim.setLoopedCount(-1);
            alphaAnim.setDelay(i * 120);
            addUpdateListener(alphaAnim, (animatorValue, v) -> {
                if (v < 0.5f)
                    alphas.set(index, (-356 * v + 255) / 255);
                else
                    alphas.set(index, (356 * v - 101) / 255);
                invalidate();
            });
            if (enableScaleAnimator) {
                animators.add(scaleAnim);
            }
            if (enableAlphaAnimator) {
                animators.add(alphaAnim);
            }
        }
        return animators;
    }

    /**
     * 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α.
     * 则点A的坐标为(a+R*cosα,b+R*sinα)
     *
     * @param width
     * @param height
     * @param radius
     * @param angle
     * @return
     */
    Point circleAt(int width, int height, float radius, double angle) {
        float x = (float) (width / 2 + radius * (Math.cos(angle)));
        float y = (float) (height / 2 + radius * (Math.sin(angle)));
        return new Point(x, y);
    }

    public void addUpdateListener(AnimatorValue animator, AnimatorValue.ValueUpdateListener updateListener) {
        mUpdateListeners.put(animator, updateListener);
    }

    public void startAnimators() {
        for (int i = 0; i < mAnimators.size(); i++) {
            AnimatorValue animator = mAnimators.get(i);
            AnimatorValue.ValueUpdateListener updateListener = mUpdateListeners.get(animator);
            if (updateListener != null) {
                animator.setValueUpdateListener(updateListener);
            }
            animator.start();
        }
        if (enableRotationAnimator) {
            AnimatorProperty animatorProperty = createAnimatorProperty();
            animatorProperty
                    .rotate(360)
                    .setDuration(4000)
                    .setLoopedCount(-1)
                    .start();
        }
    }

    @Override
    protected void releaseSource() {

    }

    public void stopAnimators() {
        if (mAnimators != null) {
            for (AnimatorValue animator : mAnimators) {
                if (animator != null) {
                    animator.end();
                }
            }
        }
    }

    public void stop() {
        stopAnimators();
    }

    public void start() {
        if (!mHasAnimators) {
            mAnimators = createAnimators();
            mHasAnimators = true;
        }
        startAnimators();
    }


}
